/*
  国能测控局放数据接入
  yuanjing
*/
const FUN = require('../comm/func');
const rCache = require('../model/redis_cache');
const DB = require('../model/model_data');
const tbDevice = require('../model/tb_device');
const dbHelp = require('../comm/db-helper');
const dataCalc = require('../comm/data-calc');
const timLib = require('../comm/time-lib');
const devManger = require('../utils/devManger');
const PMR=require('../utils/policyManger');
const mbLib = require('../comm/modbus-lib');

module.exports = class pdGnck
{
  //将数据库选项缓存到redis
  //policy 来自数据库的记录，附加了user_auth user_level字段
  //opts 数据库json字段的解析对象
  //CacheCallback 存储执行函数

  //缓存策略的db配置项到redis

  static async InitCache(policy,opts,CacheCallback)
  {
    let obj=PMR.baseParam(policy);//即将缓存到redis的参数
    //检查json选项
    if( parseInt(policy.record_limit)==0 /*||
       parseInt(opts.fetch_period)==0*/ )
    {
      console.error('wrong template params',policy.id);
      return false;
    }

    //json options参数存储
    //obj.fetch_period = opts.fetch_period;//采样周期
    obj.table = policy.table;
    obj.record_limit = policy.record_limit;//数据库条数上限

    obj.hwid = policy.master; // 设备id
    obj.hwtype = FUN.Hwid2TypeName(policy.master);
    obj.topic = '0/'+obj.hwtype+'/tx/'+obj.hwid; // mq广播地址
    obj.wlist = opts.wlist || '';   // 白名单
    obj.thd = opts.thd || ''; // 报警阈值
    obj.enable = opts.enable; // 报警开关
    // let devNum = opts.wlist.split(',')  // 多地址
    // obj.devNum = devNum.length-1;         // 地址数量
    // obj.address = devNum[0].replace('#',''); // 通信地址
    // obj.sn = 0; // 序号
    obj.address = obj.wlist.replace('#',''); // 通信地址
    //数据库处理
    dbHelp.createTab(obj.table,policy.uid);

    //缓存主站参数
    obj.hwid = policy.master;
    obj.role = 'master';
    obj.brother = policy.brother;
    CacheCallback(policy.id,policy.master,obj);//记录到缓存
    //开启定时器
    // let poyStep= await rCache.getAll(PMR.rdNode(dConf),'poyStep');

    // PMR.setSecInter(obj.policy_id,obj.fetch_period);
  }//end InitCache




  //modbus数据总分析
  // topic = {project,devType,func,devId}
  // dConf即InitCache中的obj
  // dataBuf即mq消息内容，buf对象
  static  DataIn(topic, dConf, dataBuf)
  {
    // pcyLog(func,dataBuf);

    if(topic.func == 'tx' && dataBuf[0] == 0xF1 && dataBuf[3] == 0xFF && dataBuf[5] == dConf.address) setTimeout(()=>{this.signal(dConf,dataBuf); },2000);// 监听周期发包策略来控制采集时间
    if(dConf.address.toString(16) != dataBuf[0]) return; // 过其他通信地址的包
    mbLib.mbPacketParse(func,dConf,dataBuf,async (last,sConf)=>{
      let poyStep= await rCache.getAll(PMR.rdNode(dConf),'poyStep')||{};
      if(!poyStep.stepIndx)return;
      if(last.opt == 6){
        let data = {};
        data.opt = dataBuf[1];
        data.func=(dataBuf[2]<<8)+dataBuf[3];
        data.num=(dataBuf[4]<<8)+dataBuf[5];
        data.code=(dataBuf[6]<<8)+dataBuf[7];
        // pcyLog("功能码06 ",poyStep);

        if(data.func == 752 && data.num == 2){  // 设备已激活
          if(!poyStep.state || poyStep.state == 'ok') {
            poyStep.state = "RPA";
            rCache.set(PMR.rdNode(dConf),'poyStep',poyStep,30);
            this.awkeDev(dConf,2); // 获取采集周期（2）

          }
        }

        if(data.func == 1793 && data.num == 1){// 判断已清空数据

            this.awkeDev(dConf,4); // 开始采集数据（4）

        }

        if(data.func == 1026){

          this.awkeDev(dConf,5,0); // 获取365个数据 (5-1)

        }

        return;
      }

      this.dataHandler(last,sConf,dataBuf,timLib.NowStamp()); // 处理03状态码
    })
  }//end function ModbusTx


  //普通的数据处理,
  static async dataHandler(last,dConf,data,stamp)
  {
    let poyStep= await rCache.getAll(PMR.rdNode(dConf),'poyStep')||{};

    //记数值
    let save=[];
    let regValArray={};

    let data_fmt=[2,'n'];//分割数据宽度和数据格式

    for(let i=0;i<last.regNum;i+=(data_fmt[0]/2))
    {
      let reg=Number(last.regStart)+i;
      let regVal=(Number(data[3+i*2])<<8)+Number(data[4+i*2]);

      if(data_fmt[0]==4)//不同字节长度得的处理
        regVal=(regVal<<16)+(Number(data[5+i*2])<<8)+Number(data[6+i*2]);

      if(data_fmt[1]=='f') regVal=FUN.ieee745_toFloat(regVal).toFixed(4);
      save.push({reg:reg,value:regVal,name:'#'+last.addr+':'+reg});//加入到数组
      // regValArray['#'+last.addr+':'+reg]=regVal;//构建对象，暂存数据
      regValArray[reg]=regVal;//构建对象，暂存数据
    }


    // 获取采集周期数据
    if(save[0].reg == 1344){
      poyStep.bale_num = save[0].value;
      rCache.set(PMR.rdNode(dConf),'poyStep',poyStep,30); // 设置采集周期
      this.awkeDev(dConf,3); // 清空采样次数 （3）
      return
    }



    // pcyLog(save[0]);
    if(save[0].reg == 778 || save[0].reg == 898 || save[0].reg == 1018){   // 数据汇总 3个包
      this.data364(dConf,poyStep,regValArray,last)
    }else{
      this.dataValid(dConf,poyStep,regValArray,last)  // 数据汇总有效值
    }




  }//end funciton



  static data364(dConf,poyStep,regValArray,last){  // 数据汇总 3个包
    let t = this;
    rCache.getKey(PMR.rdNode(dConf),'regVal364').then((value)=>{
      if(value) value = JSON.parse(value);
      else value = {};

      for (var x in regValArray) {

        if(x == '1141'){
          value['1141'] = regValArray[x]>>8;
          value['1142'] = regValArray[x]&0xff;
        }
        else if (x == '1140') value['1140'] = regValArray[x]/100;
        else value[x] = regValArray[x] >= 0x80 ? (256 - regValArray[x])*-1: regValArray[x];
      };


      // pcyLog(Object.keys(value).length);

      if(Object.keys(value).length == 365){


        // pcyLog(1);


        rCache.push(PMR.rdNode(dConf),'dataList',JSON.stringify(value),30);

        rCache.del(PMR.rdNode(dConf),'regVal364');
        // 删除数据库中冗余的前期数据
        // dataCalc.dbRecordTidy(dConf.uid,dConf.table,dConf.policy_id,dConf.record_limit);

        // 365数据采集完成
        if(poyStep.bale_num == 1) {t.awkeDev(dConf,6); return;}

        poyStep.bale_num--;
        rCache.set(PMR.rdNode(dConf),'poyStep',poyStep,30); //
        t.awkeDev(dConf,4)


        return;
      }

      t.awkeDev(dConf,5,Object.keys(value).length)
      rCache.setKey(PMR.rdNode(dConf),'regVal364',JSON.stringify(value),86400);
    })

  }

  static dataValid(dConf,poyStep,regValArray,last){   // 数据汇总 有效值
    let t = this;
    rCache.getKey(PMR.rdNode(dConf),'regValValid').then( async  (value)=>{
      let reg = '';
      let alarm=0;
      if(value) value = JSON.parse(value);
      else value = {};

      for (var x in regValArray) {
        if(!reg) reg =  x;
        if(x == 2354 || x == 2356 )value[x] = (regValArray[x] >= 0x8000 ? (65536 - regValArray[x])*-1: regValArray[x])/10;
        else if(x == 2355)value[x] = (regValArray[x] >= 0x8000 ? (65536 - regValArray[x])*-1: regValArray[x]);
        else if(x == 2357)value[x] = (regValArray[x] >= 0x8000 ? (65536 - regValArray[x])*-1: regValArray[x])/100;
        else if(x == 1289){ // 报警有效值

          value[x] = (regValArray[x] >= 0x8000 ? (65536 - regValArray[x])*-1: regValArray[x])/100;
          alarm = dConf.thd && value[x] >= dConf.thd ? 1 : 0;
          if(poyStep.state == 'RPA') t.alarm(dConf,value[x]);  // 只有超高频的值参与报警
        }
        else value[x] = regValArray[x];
      }

      if(Object.keys(value).length == 16){

        // delete value[1289]; // 不存报警值

        let valsObj = await rCache.fetchAll(PMR.rdNode(dConf),'dataList'); // 获取20*365数据
        rCache.del(PMR.rdNode(dConf),'dataList');
        rCache.del(PMR.rdNode(dConf),'regValValid');

        let data = [];
        for(let i in valsObj){
          let res = JSON.parse(valsObj[i]);
          if(res[1138] == (i-0+1)){
            data[i] = res;
          }else{

            rCache.del(PMR.rdNode(dConf),'dataList');
            pcyLog('数据采集错误',res[1138] == (i-0+1));
            return;

          }
          if(i==20)return;
        }


        if(data.length == 20){
          DB.newRcd(dConf.uid, dConf.table, 'hwid,policy_id,pd,addr,alarm,json,valid,stamp',
                    [dConf.hwid, dConf.policy_id, poyStep.state, last.addr, alarm,JSON.stringify(data), JSON.stringify(value), dConf.stamp]);
          PMR.policyInform('update',dConf,poyStep.state);//通知前端

          //删除数据库中冗余的前期数据
          dataCalc.dbRecordTidy(dConf.uid,dConf.table,dConf.policy_id,dConf.record_limit);

          if(poyStep.state == "RPA") poyStep.state  = 'GWAVE';
          else if(poyStep.state == "GWAVE") poyStep.state = 'UHF';
          else if(poyStep.state == "UHF") poyStep.state = 'ok';
          rCache.set(PMR.rdNode(dConf),'poyStep',poyStep,30);


          if(poyStep.state != 'ok') t.awkeDev(dConf,2); // 获取采集周期次数 （2）
          else{
            // let wlist = dConf.wlist.split(',');
            // if(dConf.devNum == dConf.sn){
              // dConf.sn = 0;
              // dConf.address = wlist[dConf.sn].replace('#','');
              // rCache.set(PMR.policyNode(dConf),'',dConf);
              pcyLog('采集结束',timLib.NowStr());
            // }
            // else{

            //   dConf.sn++;
            //   // pcyLog('采集开始',wlist[dConf.sn]);
            //   dConf.address = wlist[dConf.sn].replace('#','');
            //   rCache.set(PMR.policyNode(dConf),'',dConf);
            //   this.awkeDev(dConf,1);// 唤醒设备（1）
            // }
          };


        }else{

          pcyLog('数据采集错误 重新采集');
          t.awkeDev(dConf,2);

        }


        return;

      }


      rCache.setKey(PMR.rdNode(dConf),'regValValid',JSON.stringify(value),86400);

      let stepIndx = 0;
      if(reg == 1801){stepIndx = 7;}// 获取放电强度 (6)
      else if(reg == 2313){stepIndx = 8;}// 获取50/100Hz相关性(7)
      else if(reg == 2336){stepIndx = 9;}// 获取放电次数、背景值、背景值电压、最大值、最大值电压、多周期脉冲数(8)
      else if(reg == 2352){stepIndx = 10;}// 获取放电次数、背景值、背景值电压、最大值、最大值电压、多周期脉冲数(8)
      else return;
      t.awkeDev(dConf,stepIndx)

    })
  }


  // 发包程序
  static async awkeDev(dConf,stepIndx,idx=0){
    let poyStep= await rCache.getAll(PMR.rdNode(dConf),'poyStep')||{};
    let address = Number(dConf.address).toString(16);

    if(!stepIndx) return;
    if(stepIndx === 1){

      this.sendMq(dConf,address+" 06 02 f0 00 02 #c"); // 唤醒设备 （1）
    }
    else if(stepIndx === 2){
      this.sendMq(dConf,address+" 03 05 40 00 01 #c"); // 获取采集周期次数 （2）
    }
    else if(stepIndx === 3){
      this.sendMq(dConf,address+" 06 07 01 00 01 #c"); // 清空采样次数  （3）
    }
    else if(stepIndx === 4){// 设置数据采集（4）

      if(poyStep.state == "RPA"){// 超声波
        this.sendMq(dConf,address+" 06 04 02 00 01 #c");
      }
      else if(poyStep.state == "GWAVE"){// 地电波
        this.sendMq(dConf,address+" 06 04 02 00 11 #c");
      }
      else if(poyStep.state == "UHF"){// 超高频
        this.sendMq(dConf,address+" 06 04 02 00 31 #c");
      }

    }
    else if(stepIndx === 5){ // 获取365个数据每个包120最后一个124+1

      if(idx === 0){
        this.sendMq(dConf,address+" 03 03 0a 00 78 #c");
      }else if(idx == 120){
        this.sendMq(dConf,address+" 03 03 82 00 78 #c");
      }else if(idx == 240){
        this.sendMq(dConf,address+" 03 03 fa 00 7c #c");
      }

    }
    else if(stepIndx === 6){
      this.sendMq(dConf,address+" 03 07 09 00 06 #c");// 获取放电百分比 （6）
    }
    else if(stepIndx === 7){
      this.sendMq(dConf,address+" 03 09 09 00 01 #c");// 获取放电强度 (7)
    }
    else if(stepIndx === 8){
      this.sendMq(dConf,address+" 03 09 20 00 02 #c");// 获取50/100Hz相关性(8)
    }
    else if(stepIndx === 9){
      this.sendMq(dConf,address+" 03 09 30 00 06 #c");// 获取放电次数、背景值、背景值电压、最大值、最大值电压、多周期脉冲数(9)
    }
    else if(stepIndx === 10){
      this.sendMq(dConf,address+" 03 05 09 00 01 #c");// 获取放电次数、背景值、背景值电压、最大值、最大值电压、多周期脉冲数(9)
    }

    poyStep.stamp = timLib.NowStamp();
    poyStep.stepIndx = stepIndx;
    rCache.set(PMR.rdNode(dConf),'poyStep',poyStep,30);

  }

  //发包
  static sendMq(dConf,send){
    let dArray=send.split(' ');
    let sendArray=[];
    for(let c of dArray)
    {
      if(c=='#c')
      {
        let crc=mbLib.crc16(sendArray);
        sendArray.push(crc>>8);
        sendArray.push(crc&0xff);
      }
      else
      {
        if(!isNaN(parseInt(c,16)))
          sendArray.push(parseInt(c,16));
      }
    }
    // pcyLog('[%d] sendMq timer',dConf.policy_id,timLib.NowStr());

    PMR.mqPub(dConf.topic,Buffer.from(sendArray));


    return true;
  }


  //报警
  static alarm(dConf,val){
    if(dConf.enable!='true') return;
    let thd = dConf.thd;
    let msg = '设备异常，基本值（'+val+'dBuV）已超出阈值';
    if(thd && val >= thd){
      DB.addAlaramLog(dConf.uid, dConf.hwid, dConf.policy_id, 1, msg, dConf.stamp).then((id)=>{
        PMR.alarmReport(id,dConf);
      })
    }
  }




  //周期回调
  static async SecInter(dConf,nowStamp)
  {
    // let poyStep= await rCache.getAll(PMR.rdNode(dConf),'poyStep')||{};
    // pcyLog("aa",timLib.NowStr());
    // if(!poyStep.state || poyStep.state == 'ok'){
    //   pcyLog('开始采集',timLib.NowStr());
    //   this.awkeDev(dConf,1);// 唤醒设备（1）
    // }

    //返回false可结束定时器
  }

  static async signal(dConf){

    // if(dConf.policy_id == 761) return;
    let poyStep= await rCache.getAll(PMR.rdNode(dConf),'poyStep')||{};
    // pcyLog(dConf.policy_id,timLib.NowStr());
    if(!poyStep.state || poyStep.state == 'ok'){
      rCache.del(PMR.rdNode(dConf),'last'); // 删除周期发包last缓存
      pcyLog('开始采集',timLib.NowStr());
      dConf.stamp =  timLib.HourRounding();
      rCache.set(PMR.policyNode(dConf),'',dConf);
      this.awkeDev(dConf,1);// 唤醒设备（1）
    }
  }



}